#ifndef __MCS__FUNCTION_SIGNATURE__HPP
#define __MCS__FUNCTION_SIGNATURE__HPP

#include "Value.hpp"

/// Abstract data type that represents function identificator
class FunctionSignature : public Void
{
public:
	FunctionSignature(String const & name)
		: Void()
		, name_(name)
	{
	}

	FunctionSignature(String const & name, size_t argCount)
		: Void()
		, name_(name)
	{
		argTypes_.reserve(argCount);
	}

	void addArgumentType(Value::DataType type)
	{
		argTypes_.push_back(type);
	}

	String const & name() const
	{
		return name_;
	}
	
	size_t argumentCount() const
	{
		return argTypes_.size();
	}
	
	Value::DataType argumentType(size_t i) const
	{
		return argTypes_.at(i);
	}
	
	std::vector<Value::DataType> const & argumentTypes() const
	{
		return argTypes_;
	}

	/// Compares this signature with \p other
	/**
		Functions with different names are compared by their names. Functions 
		with equal names but different number of arguments are compared by number
		of arguments. Functions with equal names and equal number of arguments are
		compared lexicographically by types of their arguments
		(Int < Str < Bool < Real).
	*/
	int compare(FunctionSignature const & other) const
	{
		int r = name_.compare(other.name_);
		if(r != 0) return r;

		if(argTypes_.size() < other.argTypes_.size()) return -1;
		if(argTypes_.size() > other.argTypes_.size()) return +1;

		for(size_t i=0; i<argTypes_.size(); ++i)
		{
			if(argTypes_.at(i) < other.argTypes_.at(i)) return -1;
			if(argTypes_.at(i) > other.argTypes_.at(i)) return +1;
		}
		return 0;
	}

	bool operator==(FunctionSignature const & other) const
	{
		return compare(other) == 0;
	}

	bool operator!=(FunctionSignature const & other) const
	{
		return compare(other) != 0;
	}

	bool operator<(FunctionSignature const & other) const
	{
		return compare(other) < 0;
	}

	bool operator>(FunctionSignature const & other) const
	{
		return compare(other) > 0;
	}

	bool operator<=(FunctionSignature const & other) const
	{
		return compare(other) <= 0;
	}

	bool operator>=(FunctionSignature const & other) const
	{
		return compare(other) >= 0;
	}
private:
	String name_;
	std::vector<Value::DataType> argTypes_;
};

inline std::ostream & operator<<(std::ostream & stream, FunctionSignature const & sig)
{
	stream << sig.name() << '(';
	for(size_t i=0; i<sig.argumentCount(); ++i)
	{
		if(i) stream << ',';
		stream << sig.argumentType(i);
	}
	stream << ')';
	return stream;
}

#endif //__MCS__FUNCTION_SIGNATURE__HPP
